package concurrent.thread.synchronized_1;

import org.junit.Test;
import org.openjdk.jol.info.ClassLayout;

/**
 * @author LoneRanger
 * @version 1.0
 */
public class LockEscalationDemo {

	/**
	 * 偏向锁模式存在偏向锁延迟机制：HotSpot 虚拟机在启动后有个 4s
	 * 的延迟才会对每个新建的对象开启偏向锁模式。JVM启动时会进行一系列的复杂活动，比如装载配置，系统类初始化等等。
	 * 在这个过程中会使用大量synchronized
	 * 关键字对对象加锁，且这些锁大多数都不是偏向锁。为了减少初始化时间，JVM默认延时加载偏向锁。
	 *
	 * @throws InterruptedException
	 */
	@Test
	public void test1() throws InterruptedException {
		System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
		Thread.sleep(4000);
		System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
	}

	/**
	 * 调用锁对象的obj.hashCode()或System.identityHashCode(obj)
	 * 方法会导致该对象的偏向锁被撤销。因为对于一个对象，其HashCode只会生成一次并保存，偏向锁是没有地方保存hashcode的。
	 * 轻量级锁会在锁记录中记录 hashCode
	 * 重量级锁会在 Monitor 中记录 hashCode
	 * 当对象处于可偏向（也就是线程ID为0）和已偏向的状态下，调用HashCode计算将会使对象再也无法偏向：
	 * 当对象可偏向时，MarkWord将变成未锁定状态，并只能升级成轻量锁；
	 * 当对象正处于偏向锁时，调用HashCode将使偏向锁强制升级成重量锁。
	 *
	 * @throws InterruptedException
	 */
	@Test
	public void test2() throws InterruptedException {
		System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
		//HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式
		Thread.sleep(4000);
		Object obj = new Object();

		// 思考： 如果对象调用了hashCode,还会开启偏向锁模式吗
		//obj.hashCode();

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + "开始执行。。。\n"
						+ ClassLayout.parseInstance(obj).toPrintable());
				synchronized (obj) {
					// 思考： 偏向锁执行过程中，如果对象调用了hashCode，会发生什么
					obj.hashCode();
					System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n"
							+ ClassLayout.parseInstance(obj).toPrintable());
				}
				System.out.println(Thread.currentThread().getName() + "释放锁。。。\n"
						+ ClassLayout.parseInstance(obj).toPrintable());
			}
		}, "thread1").start();

		Thread.sleep(5000);
		System.out.println(ClassLayout.parseInstance(obj).toPrintable());
	}

	/**
	 *
	 */
	@Test
	public void test3() throws InterruptedException {
		System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
		//HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式
		Thread.sleep(4000);
		Object obj = new Object();
		// 思考： 如果对象调用了hashCode,还会开启偏向锁模式吗
		obj.hashCode();
		//System.out.println(ClassLayout.parseInstance(obj).toPrintable());

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + "开始执行。。。\n"
						+ ClassLayout.parseInstance(obj).toPrintable());
				synchronized (obj) {
					System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n"
							+ ClassLayout.parseInstance(obj).toPrintable());
				}
				System.out.println(Thread.currentThread().getName() + "释放锁。。。\n"
						+ ClassLayout.parseInstance(obj).toPrintable());
			}
		}, "thread1").start();

		Thread.sleep(5000);
		System.out.println(ClassLayout.parseInstance(obj).toPrintable());
	}

}
